package com.foreveross.crawl.adapter.sub.impl20140402.v3;

import java.net.URI;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import jodd.bean.BeanUtil;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import com.foreveross.crawl.adapter.AbstractAdapter;
import com.foreveross.crawl.adapter.PlaneInfoEntityBuilder;
import com.foreveross.crawl.domain.airfreight.AbstractPlaneInfoEntity;
import com.foreveross.crawl.domain.airfreight.CabinEntity;
import com.foreveross.crawl.domain.airfreight.doub.CabinRelationEntity;
import com.foreveross.crawl.domain.airfreight.doub.DoublePlaneInfoEntity;
import com.foreveross.crawl.domain.airfreight.doub.ReturnCabinEntity;
import com.foreveross.crawl.domain.airfreight.doub.ReturnDoublePlaneInfoEntity;
import com.foreveross.crawl.domain.airfreight.single.SinglePlaneInfoEntity;
import com.foreveross.crawl.enums.RouteTypeEnum;
import com.foreveross.crawl.exception.FlightInfoNotFoundException;
import com.foreveross.taskservice.common.bean.TaskModel;
import com.gargoylesoftware.htmlunit.NicelyResynchronizingAjaxController;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlPage;

/**
 * 山东航空官网适配器
 * @author guokenye
 *
 */
public class ShandongAirAdapter extends AbstractAdapter {
	public final  static long ShanDong_GradChannel=7L;
	private final static Map<String,String> NAME_CODE_MAP=new HashMap<String,String>();
	private HttpClient globalClient;//全局同一个client
	static{
		NAME_CODE_MAP.put("Y", "畅行商旅");
		NAME_CODE_MAP.put("B", "商旅易行");
		NAME_CODE_MAP.put("M", "商旅易行");
		NAME_CODE_MAP.put("H", "商旅易行");
		NAME_CODE_MAP.put("K", "好客之旅");
		NAME_CODE_MAP.put("L", "好客之旅");
		NAME_CODE_MAP.put("P", "好客之旅");
		NAME_CODE_MAP.put("Q", "好客之旅");
		NAME_CODE_MAP.put("G", "好客之旅");
		NAME_CODE_MAP.put("V", "快乐飞享");
		NAME_CODE_MAP.put("U", "快乐飞享");
		NAME_CODE_MAP.put("Z", "快乐飞享");
		NAME_CODE_MAP.put("F", "头等尊享");
		NAME_CODE_MAP.put("W","豪华经济舱");
		NAME_CODE_MAP.put("J","超值特价");
		NAME_CODE_MAP.put("R","超值特价");
		NAME_CODE_MAP.put("T","超值特价");
		NAME_CODE_MAP.put("E","超值特价");
		NAME_CODE_MAP.put("S","S促销");
		NAME_CODE_MAP.put("A","超值头等舱");
	}
	
	/**
	 * 舱位裸价，舱位税费价，舱位支付总价,打包价(双程如有舱位打包价则用打包价)
	 */
	private static String[][] Arr43 = { { "price", "totalLowestPrice", "totalHighestPrice", "fullPrice" }, { "taxesPrice", "totalLowestTaxesPrice", "totalHighestTaxesPrice", "taxesPrice" },
			{ "originalPrice", "sumLowestPrice", "sumHighestPrice", "totalFullPrice" } };
	
	public ShandongAirAdapter(TaskModel taskQueue) {
		super(taskQueue);
		// 统一处理下城市名称带三字码问题
		taskQueue.setFromCityName(taskQueue.getFromCityName().replaceAll(
				"\\(.*\\)", ""));
		taskQueue.setToCityName(taskQueue.getToCityName().replaceAll(
				"\\(.*\\)", ""));
	}
	@SuppressWarnings("incomplete-switch")
	@Override
	public Object fetch(String url) throws Exception {
		switch(super.getRouteType()){
		case INTERNATIONAL_ONEWAY:
		case INTERNATIONAL_ROUND:
			return fetchInternational();
		case DOMESTIC_ONEWAYTRIP:
			return fetchDomeOneWayBeta1();//fetchDomeOneWay();
		}
		return null;
	}
	/**
	 * 进入国内数据
	 * @return
	 * @throws Exception
	 */
	private Object fetchDomeOneWay()throws Exception{
		HttpClient h;
		HttpGet g = null;
		String url = null;
		String page;
		Document doc;
		String airAvailId;
		try{
			h=getHttpClient();
			g=new HttpGet();
			url="http://sc.travelsky.com/scet/queryAv.do?"+
					"adultNum=1&childNum=0&comeFrom=&countrytype=1&returnDate=&travelType=0"+
					"&cityCodeOrg="+taskQueue.getFromCity()+
					"&cityCodeDes="+taskQueue.getToCity()+
					"&cityNameOrg="+URLEncoder.encode(taskQueue.getFromCityName(),"GBK")+
					"&cityNameDes="+URLEncoder.encode(taskQueue.getToCityName(),"gbk")+
					"&takeoffDate="+taskQueue.getFlightDate();
			g.setURI(new URI(url));
			g.setHeader("Host","sc.travelsky.com");
			g.setHeader("Referer","http://sc.travelsky.com/scet/queryAvInternational.do");
			g.setHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64; rv:25.0) Gecko/20100101 Firefox/25.0");
			g.setHeader("Accept-Language","zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3");
			page=excuteRequest(h, g, true);
			doc=Jsoup.parse(page);
			airAvailId=doc.getElementsByAttributeValue("name", "airAvailId").first().attr("value");
			if(airAvailId!=null && !"".equals(airAvailId.trim())){
				url="http://sc.travelsky.com/scet/airAvail.do?"+
						"adultNum=1&cabinStage=0&childNum=0&countrytype=0&step=0&needRT=0&travelType=0usefor=1"+
						"&cityCodeOrg="+taskQueue.getFromCity()+
						"&cityCodeDes="+taskQueue.getToCity()+
						"&cityNameOrg="+URLEncoder.encode(taskQueue.getFromCityName(),"GBK")+
						"&cityNameDes="+URLEncoder.encode(taskQueue.getToCityName(),"gbk")+
						"&takeoffDate="+taskQueue.getFlightDate()+
						"&&returnDate="+taskQueue.getFlightDate()+
						"&airAvailId="+airAvailId;
				g.setURI(new URI(url));
				page=excuteRequest(h, g, true);
				if(page!=null){
					super.appendPageContents(page);
					super.setLenghtCount(page.length());
				}
			}else{
				throw new Exception("国内数据拿不到key");
			}
		}finally{
			url=null;
			if(g!=null){g.releaseConnection();g=null;}
			h=null;
		}
		return page;
	}
	
	private Object fetchDomeOneWayBeta1() throws Exception{
		String url = null;
		WebClient webClient = null;
		HtmlPage page = null;
		String html = null;
		try{
			 url="http://sc.travelsky.com/scet/queryAv.do?"+
					"adultNum=1&childNum=0&comeFrom=&countrytype=1&returnDate=&travelType=0"+
					"&cityCodeOrg="+taskQueue.getFromCity()+
					"&cityCodeDes="+taskQueue.getToCity()+
					"&cityNameOrg="+URLEncoder.encode(taskQueue.getFromCityName(),"GBK")+
					"&cityNameDes="+URLEncoder.encode(taskQueue.getToCityName(),"gbk")+
					"&takeoffDate="+taskQueue.getFlightDate();
			 webClient = super.getWebClientByFF();
			webClient.getOptions().setRedirectEnabled(true);
			webClient.getOptions().setJavaScriptEnabled(true);
			webClient.getOptions().setActiveXNative(false);
			webClient.getOptions().setCssEnabled(false);
			webClient.getOptions().setThrowExceptionOnScriptError(false);
			webClient.getCookieManager().setCookiesEnabled(true);
			 page = webClient.getPage(url);
			 html = page.asXml();
			 super.appendPageContents(html);
			 return html;
		}finally{
			 url = null;
			 webClient = null;
			 page = null;
		}
	}
	
	/**
	 * 进入国际数据
	 * 返回htmlStirng
	 * 
	 * @return
	 * @throws Exception
	 */
	private Object fetchInternational()throws Exception{
		HttpClient h;
		HttpGet g = null;
		String url = null;
		String page;
		try{
			h=super.getHttpClient();
			g=new HttpGet();
			if(super.getRouteType()==RouteTypeEnum.INTERNATIONAL_ROUND){
				url="http://sc.travelsky.com/scet/queryAvInternational.do?"+
						"adultNum=1&cabinStage=0&childNum=0&comeFrom=&countrytype=1&nextday=&step=0&travelType=1&usefor=1"+
						"&cityCodeOrg="+taskQueue.getFromCity()+
						"&cityCodeDes="+taskQueue.getToCity()+
						"&cityNameOrg="+URLEncoder.encode(taskQueue.getFromCityName(),"GBK")+
						"&cityNameDes="+URLEncoder.encode(taskQueue.getToCityName(),"gbk")+
						"&takeoffDate="+taskQueue.getFlightDate()+
						"&returnDate="+taskQueue.getReturnGrabDate();
			}else{
				url="http://sc.travelsky.com/scet/queryAvInternational.do?"+
						"adultNum=1&cabinStage=0&childNum=0&comeFrom=&countrytype=1&nextday=&step=0&returnDate=&travelType=0&usefor=1"+
						"&cityCodeOrg="+taskQueue.getFromCity()+
						"&cityCodeDes="+taskQueue.getToCity()+
						"&cityNameOrg="+URLEncoder.encode(taskQueue.getFromCityName(),"GBK")+
						"&cityNameDes="+URLEncoder.encode(taskQueue.getToCityName(),"gbk")+
						"&takeoffDate="+taskQueue.getFlightDate();
			}
			g.setURI(new URI(url));
			g.setHeader("Host","sc.travelsky.com");
			g.setHeader("Referer","http://sc.travelsky.com/scet/queryAvInternational.do");
			g.setHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64; rv:25.0) Gecko/20100101 Firefox/31.0");
			g.setHeader("Accept-Language","zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3");
			page=excuteRequest(h, g, true);
			if(page!=null){
				super.appendPageContents(page);
				super.setLenghtCount(page.length());
			}
		}finally{
			url=null;
			if(g!=null){g.releaseConnection();g=null;}
			h=null;
		}
		return page;
	}
	

	@Override
	public boolean validateFetch(Object obj) throws Exception {
		if(obj==null || obj.toString().trim() == ""){
			throw new  Exception("山东航空抓取数据为空");
		}
//		if(obj.toString().replaceAll("\\s", "").matches(".*请查询山航航班.*")){
//			throw new FlightInfoNotFoundException();
//		}
		Document doc=Jsoup.parse(obj.toString());;
		switch(super.getRouteType()){
		case DOMESTIC_ONEWAYTRIP:
			if(obj.toString().replaceAll("\\s", "").matches(".*未能查询到航班信息.*")){
				throw new FlightInfoNotFoundException();
			}
			break;
		
		
		case INTERNATIONAL_ONEWAY:
		case INTERNATIONAL_ROUND:
			Elements tbs = null;
			try{
				if(doc.html().replaceAll("\\s", "").matches(".*国际航班查询出错:输入参数错误.*")){
					throw new FlightInfoNotFoundException("国际航班查询出错:输入参数错误");
				}
				tbs=doc.getElementsByClass("mg-bottom14");
				if(tbs==null || tbs.size()==0){
					throw new Exception("找不到结果table class='mg-bottom14'");
				}
				if(super.getRouteType()==RouteTypeEnum.INTERNATIONAL_ROUND && tbs.size()!=2){
					throw new Exception("国际往返结果不全");
				}
				
				if(super.getRouteType()==RouteTypeEnum.INTERNATIONAL_ONEWAY){
					if(tbs.first().html().replaceAll("\\s", "").matches(".*Sorry,nosearchresultsmatchyourquery.*") ||
							tbs.first().html().replaceAll("\\s", "").matches(".*很抱歉，没有符合条件的查询结果 .*")	
							){
						throw new FlightInfoNotFoundException();
					}
				}else{
					if((tbs.first().html().replaceAll("\\s", "").matches(".*Sorry,nosearchresultsmatchyourquery.*") ||
							tbs.first().html().replaceAll("\\s", "").matches(".*很抱歉，没有符合条件的查询结果 .*"))	
							&&
							(tbs.get(1).html().replaceAll("\\s", "").matches(".*Sorry,nosearchresultsmatchyourquery.*") ||
									tbs.get(1).html().replaceAll("\\s", "").matches(".*很抱歉，没有符合条件的查询结果 .*")
									)
								){
						throw new FlightInfoNotFoundException();
					}
				}
			}finally{
				tbs=null;
				doc=null;
			}
			break;
		}
		return true;
	}
	
	@Override
	public List<Object> paraseToVo(Object obj) throws Exception {
		switch(super.getRouteType()){
		case INTERNATIONAL_ROUND:
			return paraseInterRound(obj);
		case INTERNATIONAL_ONEWAY:
			return paraseInterOneWay(obj);
		case DOMESTIC_ONEWAYTRIP:
			return paraseDomeOneWay(obj);
		}
		return null;
	}

	
	private List<Object> paraseDomeOneWay(Object obj)throws Exception{
		List<Object> result = new ArrayList<Object>();
		Document doc = null;
		Elements divs;
		try {
			doc = Jsoup.parse(obj.toString());
			divs = doc.getElementsByAttributeValue("class", "record");
			Double fixedTaxes=null;
			String fixedTaxesStr=doc.select("div[data-tax]").first().attr("data-tax");
			fixedTaxes=Double.parseDouble(fixedTaxesStr.trim());
			for (Element div : divs) {
				String flightNo;
				String type = null;
				String time;
				String start;
				String end;
				String carrierFullName = null;
				Elements imgCarriers;
				Elements cabinDivs;
				SinglePlaneInfoEntity singleEntity;
				CabinEntity cabinEntity;
				String key;
				boolean isExist=false;
				try {
					flightNo = div.getElementsByAttributeValue("class", "dashed").first().html();
					imgCarriers = div.select("img.absolute");
					if(imgCarriers != null && imgCarriers.size() != 0){
						carrierFullName = imgCarriers.first().attr("title");
						carrierFullName = carrierFullName.split(" ")[1].replaceAll("由", "").replaceAll("实际承运", "");
					}
					//有些由其他航空公司承运的没有机型
					try{
						type = getPlaneType(div.getElementsByAttributeValue("class", "popup").first());
					}catch(Exception e){
						logger.error(e);
					}
					time = div.getElementsByAttributeValue("class", "time").first().text();
					start = time.split(" ")[0].trim();
					end = time.split(" ")[1].trim();
					singleEntity=(SinglePlaneInfoEntity) getEntity(flightNo,result);
					if(singleEntity==null){
						singleEntity=(SinglePlaneInfoEntity) PlaneInfoEntityBuilder.buildPlaneInfo(taskQueue, 
								flightNo.substring(0,2), "山航", "山东航空公司", start, end, flightNo, null, "山航自营", null, type);
						//2014-09-25 目前不考虑其它公司实际承运情况，以后如果需要，则去掉注释部分
//						if(carrierFullName != null){
//							singleEntity.setCarrierFullName(carrierFullName);
//							singleEntity.setCarrierKey(null);
//							singleEntity.setCarrierName(null);
//							singleEntity.setAgentName(null);
//						}
					}else{
						isExist=true;
					}
					//解析页面仓位
					cabinDivs= div.getElementsByAttributeValueMatching("class","^rdo-trigger.*");
					try{
						for(Element e:cabinDivs){
							cabinEntity=new CabinEntity();
							cabinEntity.setSubCabinName(e.attr("data-classcode"));
							cabinEntity.setProductName(NAME_CODE_MAP.get(cabinEntity.getSubCabinName()));
							if(cabinEntity.getProductName()!=null){
								cabinEntity.setCabinType(cabinEntity.getProductName().matches(".*头等.*")?"头等舱":"经济舱");
							}
							cabinEntity.setPrice(Double.valueOf(e.attr("data-price")));
							cabinEntity.setOriginalPrice(Double.valueOf(e.attr("data-total")));
							cabinEntity.setTuigaiqian(e.attr("data-remark"));
							cabinEntity.setLastSeatInfo(e.getElementsByTag("span").last().text().trim());
							singleEntity.getCabins().add(cabinEntity);
						}
						if(!isExist){
							//获取来自网页的更多仓位数据
							//key=div.getElementsByClass("showallcabin").first().attr("coordinate");
							//setCabinDataByNet(singleEntity,key);
						}
					}catch(Exception e){
						logger.error(e);
						throw e;
					}
					//增加最低价与最高价字段值
					setTotalPriceByCabinPrice(singleEntity);
					//新增字段，将裸价加上税费
					fillTaxesDataForDomestic(singleEntity,fixedTaxes);
					result.add(singleEntity);
				} finally{
					flightNo=null;
					type=null;
					time=null;
					start=null;
					end=null;
					cabinDivs=null;
					singleEntity=null;
					cabinEntity=null;
					key=null;
				}
			}
		} finally {
			divs=null;
			doc = null;
		}
		return result;
	}
	
	private AbstractPlaneInfoEntity getEntity(String flightNo,List<Object> result){
		if(flightNo==null || result==null ||result.isEmpty()){
			return null;
		}
		for(Object o:result){
			AbstractPlaneInfoEntity entity=(AbstractPlaneInfoEntity)o;
			if(flightNo.equals(entity.getFlightNo())){
				return (AbstractPlaneInfoEntity)o;
			}
		}
		return null;
	}
	
	/**
	 * 从网络获取更多的仓位资源信息
	 * @param entity
	 */
	@SuppressWarnings({ "unchecked", "deprecation" })
	private void setCabinDataByNet(AbstractPlaneInfoEntity entity,String key){
		
		HttpGet g = null;
		String cabinStr;
		JSONObject cabinJson;
		JSONObject economyClass;
		JSONArray[] arrays = null;
		JSONObject cabin;
		CabinEntity cabinEntity;
		try{
			g=new HttpGet("http://sc.travelsky.com/scet/airAvailDetails.do?coordinate="+URLEncoder.encode(key));
			g.setHeader("Host","sc.travelsky.com");
			g.setHeader("Pragma","no-cache");
			g.setHeader("Referer","http://sc.travelsky.com/scet/airAvail.do");
			g.setHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64; rv:25.0) Gecko/20100101 Firefox/25.0");
			g.setHeader("X-Requested-With","XMLHttpRequest");
			g.setHeader("Accept-Language","zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3");
			cabinStr=excuteRequest(getHttpClient(), g, true);
			cabinJson=JSONObject.fromObject(cabinStr);
			economyClass=cabinJson.getJSONObject("flightVo").getJSONObject("economyClass");
			arrays=new JSONArray[economyClass.values().size()];
			economyClass.values().toArray(arrays);
			for(JSONArray array:arrays){
				for(int i=0;i<array.size();i++){
					cabin=array.getJSONObject(i);
					cabinEntity=new CabinEntity();
					cabinEntity.setProductName(cabin.getString("productName"));
					cabinEntity.setSubCabinName(cabin.getString("classCode"));
					cabinEntity.setPrice(cabin.getJSONObject("fare").getDouble("adultAmount"));
					if(cabinEntity.getProductName()!=null){
						cabinEntity.setCabinType(cabinEntity.getProductName().matches(".*头等.*")?"头等舱":"经济舱");
					}
					((SinglePlaneInfoEntity)entity).getCabins().add(cabinEntity);
				}
			}
		}catch(Exception e){
			logger.error(e);
		}finally{
			cabinStr=null;
			cabinJson=null;
			economyClass=null;
			arrays = null;
			cabin=null;
			cabinEntity=null;
			if(g!=null){
				g.releaseConnection();g=null;
			}
		}
	}
	
	
	
	private String getPlaneType(Element e){
		if(e==null || e.html()==null || "".equals(e.html().trim())){return null;}
		String text=e.html().replaceAll("\\s", "");
		int start=text.indexOf("机型：");
		int end=text.indexOf("<",start+3);
		return text.substring(start+3,end);
	}
	
	private List<Object> paraseInterOneWay(Object obj)throws Exception{
		List<Object> result=new ArrayList<Object>();
		Document doc;
		Element table;
		List<SinglePlaneInfoEntity> sps;
		try{
			doc=Jsoup.parse(obj.toString());
//			System.out.println(doc);
			table=doc.getElementsByClass("mg-bottom14").first();//去程table
			Map<AbstractPlaneInfoEntity,Map<Object,Object>> gotoPlaneCbeMap=new HashMap<AbstractPlaneInfoEntity,Map<Object,Object>>();
			sps=this.getDoubleOrReturnEntity(table, SinglePlaneInfoEntity.class,gotoPlaneCbeMap);
			if(sps!=null && !sps.isEmpty()){
				for(SinglePlaneInfoEntity sp:sps){
					//setTotalPriceByCabinPrice(sp);
					for(Entry<Object,Object> gotoEntry:gotoPlaneCbeMap.get(sp).entrySet()){
						fillTaxesDataForNational(sp,gotoEntry, null);
					}
					countPlanePriceDataByCabinPrice(sp);
					result.add(sp);
				}
			}
		}finally{
			doc=null;
			table=null;
			sps=null;
 		}
		return result;
	}
	
	private List<Object> paraseInterRound(Object obj)throws Exception{
			
		List<Object> result=new ArrayList<Object>();
		Document doc;
		Element table1;
		Element table2;
		List<DoublePlaneInfoEntity> dps;
		List<ReturnDoublePlaneInfoEntity> reDps;
		try{
			doc=Jsoup.parse(obj.toString());
			table1=doc.getElementsByClass("mg-bottom14").first();//去程table
			table2=doc.getElementsByClass("mg-bottom14").get(1);//回程table
			
			Map<AbstractPlaneInfoEntity,Map<Object,Object>> gotoPlaneCbeMap=new HashMap<AbstractPlaneInfoEntity,Map<Object,Object>>();
			Map<AbstractPlaneInfoEntity,Map<Object,Object>> returnPlaneCbeMap=new HashMap<AbstractPlaneInfoEntity,Map<Object,Object>>();
			
			dps=getDoubleOrReturnEntity(table1,DoublePlaneInfoEntity.class,gotoPlaneCbeMap);
			reDps=getDoubleOrReturnEntity(table2,ReturnDoublePlaneInfoEntity.class,returnPlaneCbeMap);
			
			if(dps!=null && !dps.isEmpty()){
				for(DoublePlaneInfoEntity dp:dps){
					//山东是很明显的来回阶乘，我们需要分别设置设置极限价格
					if(reDps!=null && !reDps.isEmpty()){//有可能没有回程
						for(ReturnDoublePlaneInfoEntity redp:reDps){
							for(Entry<Object,Object> gotoEntry:gotoPlaneCbeMap.get(dp).entrySet()){
								for(Entry<Object,Object> returnEntry:returnPlaneCbeMap.get(redp).entrySet()){
									//去程与返程组合两个step字符串找出数据
									fillTaxesDataForNational(dp,gotoEntry, returnEntry);
								}
							}
						}
						countPlanePriceDataByCabinPrice(dp);
						dp.getReturnPlaneInfos().addAll(reDps);
						//setTotalPriceByCabinPrice(dp);
					}
					result.add(dp);
				}
			}
		}finally{
			doc=null;
			table1=null;
			table2=null;
			dps=null;
			reDps=null;
		}
		return result;
	}
	private void setTotalPriceByCabinPrice(AbstractPlaneInfoEntity entity)
			throws Exception {
		List<Double> fromPrice = new ArrayList<Double>();
		List<Double> toPrice = new ArrayList<Double>();
		SinglePlaneInfoEntity singleEntity;
		DoublePlaneInfoEntity doubleEntity;
		try {
			if (entity instanceof SinglePlaneInfoEntity) {
				singleEntity = (SinglePlaneInfoEntity) entity;
				for (CabinEntity cb : singleEntity.getCabins()) {
					if (cb != null && cb.getPrice() != null) {
						fromPrice.add(cb.getPrice());
					}
				}
				if (!fromPrice.isEmpty()) {
					entity.setTotalLowestPrice(getPriceByType(fromPrice,
							"lower"));
					entity.setTotalHighestPrice(getPriceByType(fromPrice,
							"hight"));
				}

			} else if (entity instanceof DoublePlaneInfoEntity) {
				doubleEntity = (DoublePlaneInfoEntity) entity;
				for (CabinEntity cb : doubleEntity.getCabins()) {
					if (cb != null && cb.getPrice() != null) {
						fromPrice.add(cb.getPrice());
					}
				}
				for (ReturnDoublePlaneInfoEntity reEntity : doubleEntity
						.getReturnPlaneInfos()) {
					for (ReturnCabinEntity reCb : reEntity.getReturnCabins()) {
						if (reCb != null && reCb.getPrice() != null) {
							toPrice.add(reCb.getPrice());
						}
					}
				}
				if (!fromPrice.isEmpty() && !toPrice.isEmpty()) {
					entity.setTotalLowestPrice(getPriceByType(fromPrice,
							"lower") + getPriceByType(toPrice, "lower"));
					entity.setTotalHighestPrice(getPriceByType(fromPrice,
							"hight") + getPriceByType(toPrice, "hight"));
				}
			}

		} finally {
			fromPrice.clear();
			fromPrice = null;
			toPrice.clear();
			toPrice = null;
			singleEntity = null;
			doubleEntity = null;
		}
	}

    /**
     * 新增字段，对往返舱位为裸价加上税费，总价等, (国际)
     * @param gotoCabinEntry
     * @param returnCabinEntry
     * @throws Exception
     */
	private void fillTaxesDataForNational(AbstractPlaneInfoEntity planeinfo,Entry<Object,Object>  gotoCabinEntry,Entry<Object,Object>  returnCabinEntry) throws Exception{
		Map<String,String> paras=new HashMap<String, String>();
		if(null!=gotoCabinEntry){
			paras.put("firststepcabininfo", (String)gotoCabinEntry.getValue());
		}
		if(null!=returnCabinEntry){
			paras.put("secondstepcabininfo", (String)returnCabinEntry.getValue());
		}
		
		paras.put("countrytype", taskQueue.getIsInternational()+"");
		paras.put("journeytype", taskQueue.getIsReturn()+"");
		paras.put("fromQQ", "0");
		paras.put("fromAlipay", "0");
		paras.put("fromChinapay", "0");
		paras.put("hasBankFav", "0");
		
		String url="http://sc.travelsky.com/scet/psgInfoFillInternational.do";
		HttpPost post=getBasePost(url, paras);
		post.setHeader("Host","sc.travelsky.com");
		post.setHeader("Referer","http://sc.travelsky.com/scet/queryAvInternational.do");
		post.setHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64; rv:25.0) Gecko/20100101 Firefox/25.0");
		post.setHeader("Accept-Language","zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3");
		String page=excuteRequest(getHttpClient(), post, true);
		if(page!=null){
			String appendStr="\r\n------>\r\n"+page;
			super.appendPageContents(appendStr);
			super.setLenghtCount(appendStr.length());
		}
		
		Document doc=Jsoup.parse(page, "http://sc.travelsky.com");
		Elements priceTrEles=doc.select("tr.flow_td_bg01");
	    String planePriceContainTaxesStr=null;
		String planePriceContainTaxes=null;
		
	    //fill taxes relate data 
		CabinEntity cbe=null;
		if(null!=gotoCabinEntry){
			planePriceContainTaxesStr=priceTrEles.first().child(5).text();
			planePriceContainTaxes=planePriceContainTaxesStr.substring(planePriceContainTaxesStr.indexOf("￥")+1).trim();
			double originalPrice=Double.parseDouble(planePriceContainTaxes);
			cbe=(CabinEntity)gotoCabinEntry.getKey();
			cbe.setTaxesPrice(originalPrice-cbe.getPrice());
			cbe.setOriginalPrice(originalPrice);
		}
		ReturnCabinEntity rcbe=null;
		if(null!=returnCabinEntry){
			planePriceContainTaxesStr=priceTrEles.get(1).child(5).text();
			planePriceContainTaxes=planePriceContainTaxesStr.substring(planePriceContainTaxesStr.indexOf("￥")+1).trim();
			double originalPrice=Double.parseDouble(planePriceContainTaxes);
			rcbe=(ReturnCabinEntity)returnCabinEntry.getKey();
			rcbe.setTaxesPrice(originalPrice-rcbe.getPrice());
			rcbe.setOriginalPrice(originalPrice);
			
			CabinRelationEntity cr=new CabinRelationEntity();
			cr.setTaxesPrice(cbe.getTaxesPrice()+rcbe.getTaxesPrice());
			cr.setFullPrice(cbe.getPrice()+rcbe.getPrice());
			cr.setTotalFullPrice(cbe.getOriginalPrice()+rcbe.getOriginalPrice());
			((DoublePlaneInfoEntity)planeinfo).getCabinRelations().add(cr);
		}
			
	}
	
	/**
	 * 实体装箱
	 * @param table
	 * @param c
	 * @return
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	private <T extends AbstractPlaneInfoEntity> List<T> getDoubleOrReturnEntity(Element table,Class<T> c,Map<AbstractPlaneInfoEntity,Map<Object,Object>> planeCbeMap)throws Exception{
		List<T> result=new ArrayList<T>();
		for(Element tb:table.getElementsByClass("flow0_chaxun_tab060")){
			Element temp;
			String flightNo;
			String start;
			String end;
			String type;
			SinglePlaneInfoEntity singlePlaneInfoEntity=null;
			DoublePlaneInfoEntity doublePlaneInfoEntity = null;
			ReturnDoublePlaneInfoEntity retuenDoublePlaneInfoEntity = null;
			CabinEntity cabinEntity;
			ReturnCabinEntity returnCabinEntity;
			Map<Object,Object> cbeMap=new HashMap<Object, Object>();
			try{
				temp=tb.select("tr").first();
				flightNo=temp.child(0).text().replaceAll("\\W", "");
				start=temp.child(1).text().split(" ")[0].replaceAll("\\s", "");
				end=temp.child(1).text().split(" ")[1].replaceAll("\\s", "");
				type=temp.child(2).select("span").first().text();
				if(c.equals(DoublePlaneInfoEntity.class)){
					doublePlaneInfoEntity=(DoublePlaneInfoEntity) PlaneInfoEntityBuilder.buildPlaneInfo(taskQueue, 
							flightNo.substring(0,2), "山航", "山东航空公司", start, end, flightNo, null, "山航自营", null, type);
					result.add((T) doublePlaneInfoEntity);
				}else if(c.equals(ReturnDoublePlaneInfoEntity.class)){
					retuenDoublePlaneInfoEntity=PlaneInfoEntityBuilder.getReturnTrip(taskQueue, 
							flightNo.substring(0,2), "山航", "山东航空公司", start, end, flightNo, null, "山航自营", null, type);
					result.add((T) retuenDoublePlaneInfoEntity);
				}else if(c.equals(SinglePlaneInfoEntity.class)){
					singlePlaneInfoEntity=(SinglePlaneInfoEntity) PlaneInfoEntityBuilder.buildPlaneInfo(taskQueue, 
							flightNo.substring(0,2), "山航", "山东航空公司", start, end, flightNo, null, "山航自营", null, type);
					result.add((T) singlePlaneInfoEntity);
				}
				for(Element tr:temp.child(4).select("tr")){
					if(c.equals(DoublePlaneInfoEntity.class) || c.equals(SinglePlaneInfoEntity.class)){
						cabinEntity=new CabinEntity();
						cabinEntity.setSubCabinName(tr.child(0).text().replaceAll("\\W", "").replaceAll("\\d", ""));
						cabinEntity.setPrice(
								Double.valueOf(tr.child(0).select("span").first().text().replaceAll("\\s", "").replaceAll("^￥", "")));
						cabinEntity.setTuigaiqian(tr.child(1).text());
						cabinEntity.setLastSeatInfo(tr.child(2).text());
						
						String cabininfo= tr.select("input[name=select0]").get(0).val();
						cbeMap.put(cabinEntity, cabininfo);
						if(singlePlaneInfoEntity!=null){
							singlePlaneInfoEntity.getCabins().add(cabinEntity);
							planeCbeMap.put(singlePlaneInfoEntity, cbeMap);
						}else if(doublePlaneInfoEntity!=null){
							doublePlaneInfoEntity.getCabins().add(cabinEntity);
							planeCbeMap.put(doublePlaneInfoEntity, cbeMap);
						}
						
						
					}else if(c.equals(ReturnDoublePlaneInfoEntity.class)){
						returnCabinEntity=new ReturnCabinEntity();
						returnCabinEntity.setSubCabinName(tr.child(0).text().replaceAll("\\W", "").replaceAll("\\d", ""));
						returnCabinEntity.setPrice(
								Double.valueOf(tr.child(0).select("span").first().text().replaceAll("\\s", "").replaceAll("^￥", "")));
						returnCabinEntity.setTuigaiqian(tr.child(1).text());
						returnCabinEntity.setLastSeatInfo(tr.child(2).text());
						retuenDoublePlaneInfoEntity.getReturnCabins().add(returnCabinEntity);
						String cabininfo= tr.select("input[name=select1]").get(0).val();
						cbeMap.put(returnCabinEntity, cabininfo);
						planeCbeMap.put(retuenDoublePlaneInfoEntity, cbeMap);
					}
				}
			}catch(Exception e){
				logger.error(e.getMessage());
			}finally{
				temp= null;
				flightNo= null;
				start= null;
				end= null;
				type= null;
				doublePlaneInfoEntity = null;
				retuenDoublePlaneInfoEntity = null;
				cabinEntity= null;
				returnCabinEntity= null;
			}
		}
		return result;
	}
	
	/**
	 * 新增字段，将裸价加上税费, (国内)
	 * 
	 * @param entity
	 * @throws Exception
	 */
	protected void fillTaxesDataForDomestic(AbstractPlaneInfoEntity entity, double fixedTaxes) throws Exception {
		if (entity instanceof SinglePlaneInfoEntity) {
			Set<CabinEntity> cabins = ((SinglePlaneInfoEntity) entity).getCabins();
			for (CabinEntity cbe : cabins) {
				cbe.setTaxesPrice(fixedTaxes);
				cbe.setOriginalPrice(cbe.getPrice() + fixedTaxes);
			}
			// 兼容没有统计裸价的情况，先统计之
			if (null == entity.getTotalLowestPrice() || null == entity.getTotalHighestPrice()) {
				this.countPlanePriceDataByCabinPrice(entity, Arr43[0]);
			}
			entity.setTotalLowestTaxesPrice(fixedTaxes);
			entity.setSumLowestPrice(entity.getTotalLowestPrice() + fixedTaxes);
			entity.setTotalHighestTaxesPrice(fixedTaxes);
			entity.setSumHighestPrice(entity.getTotalHighestPrice() + fixedTaxes);

		} else if (entity instanceof DoublePlaneInfoEntity) {
			// 新增字段，将裸价加上税费
			Set<CabinEntity> cabins = ((DoublePlaneInfoEntity) entity).getCabins();
			for (CabinEntity cbe : cabins) {
				cbe.setTaxesPrice(fixedTaxes);
				cbe.setOriginalPrice(cbe.getPrice() + fixedTaxes);

				for (ReturnDoublePlaneInfoEntity returnPlaneEntity : ((DoublePlaneInfoEntity) entity).getReturnPlaneInfos()) {
					Set<ReturnCabinEntity> retCabins = returnPlaneEntity.getReturnCabins();
					for (ReturnCabinEntity rcbe : retCabins) {
						rcbe.setTaxesPrice(fixedTaxes);
						rcbe.setOriginalPrice(rcbe.getPrice() + fixedTaxes);
						// 兼容没有设置打包价的情况
						if (null != rcbe) {
							CabinRelationEntity cr = new CabinRelationEntity();
							cr.setTaxesPrice(cbe.getTaxesPrice() + rcbe.getTaxesPrice());
							cr.setFullPrice(cbe.getPrice() + rcbe.getPrice());
							cr.setTotalFullPrice(cbe.getOriginalPrice() + rcbe.getOriginalPrice());
							((DoublePlaneInfoEntity) entity).getCabinRelations().add(cr);
						}
					}

				}

			}
			// 兼容没有统计裸价的情况，先统计之
			if (null == entity.getTotalLowestPrice() || null == entity.getTotalHighestPrice()) {
				this.countPlanePriceDataByCabinPrice(entity, Arr43[0]);
			}
			entity.setTotalLowestTaxesPrice(fixedTaxes * 2);
			entity.setSumLowestPrice(entity.getTotalLowestPrice() + fixedTaxes * 2);
			entity.setTotalHighestTaxesPrice(fixedTaxes * 2);
			entity.setSumHighestPrice(entity.getTotalHighestPrice() + fixedTaxes * 2);

		} else ;

	}
	
	/**
	 * 将舱位的价格数据，进行统计后设置为航班的统计数据
	 * 
	 * @param entity
	 * @throws Exception
	 */
	protected void countPlanePriceDataByCabinPrice(AbstractPlaneInfoEntity entity) throws Exception {
		for (String[] arr : Arr43) {
			countPlanePriceDataByCabinPrice(entity, arr);
		}
	}

	/**
	 * 将舱位的价格数据，进行统计后设置为航班的统计数据(用了反射取值，让结构更简单,在高性能要求时,可将其改成手工取值,让代码冗余)
	 * 
	 * @param entity
	 * @param <XX价格，XX最低价，XX最高价>
	 * @throws Exception
	 */
	protected void countPlanePriceDataByCabinPrice(AbstractPlaneInfoEntity entity, String[] arr) throws Exception {
		List<Double> fromPrice = new ArrayList<Double>();// 去程价格
		List<Double> toPrice = new ArrayList<Double>(); // 返程价格
		List<Double> fromToPrice = new ArrayList<Double>(); // 去程+返程价格
		SinglePlaneInfoEntity singleEntity;
		DoublePlaneInfoEntity doubleEntity;

		try {
			if (entity instanceof SinglePlaneInfoEntity) {
				singleEntity = (SinglePlaneInfoEntity) entity;
				for (CabinEntity cb : singleEntity.getCabins()) {
					Double cbePrice = (Double) BeanUtil.getProperty(cb, arr[0]);
					if (cb != null && cbePrice != null) {
						fromPrice.add(cbePrice);
					}
				}
				if (!fromPrice.isEmpty()) {
					BeanUtil.setProperty(entity, arr[1], getPriceByType(fromPrice, "lower"));
					BeanUtil.setProperty(entity, arr[2], getPriceByType(fromPrice, "hight"));
				}

			} else if (entity instanceof DoublePlaneInfoEntity) {
				doubleEntity = (DoublePlaneInfoEntity) entity;
				// 如有打包价，则按打包价，否则按去返程和之价，便于兼容
				if (null != doubleEntity.getCabinRelations() && doubleEntity.getCabinRelations().size() > 0) {
					for (CabinRelationEntity cbeRelation : doubleEntity.getCabinRelations()) {
						Double cbePrice = (Double) BeanUtil.getProperty(cbeRelation, arr[3]);
						fromToPrice.add(cbePrice);
					}
					BeanUtil.setProperty(entity, arr[1], getPriceByType(fromToPrice, "lower"));
					BeanUtil.setProperty(entity, arr[2], getPriceByType(fromToPrice, "hight"));
					return;
				}

				for (CabinEntity cb : doubleEntity.getCabins()) {
					Double cbePrice = (Double) BeanUtil.getProperty(cb, arr[0]);
					if (cb != null && cbePrice != null) {
						fromPrice.add(cbePrice);
					}
				}
				for (ReturnDoublePlaneInfoEntity reEntity : doubleEntity.getReturnPlaneInfos()) {
					for (ReturnCabinEntity reCb : reEntity.getReturnCabins()) {
						Double cbePrice = (Double) BeanUtil.getProperty(reCb, arr[0]);
						if (reCb != null && cbePrice != null) {
							toPrice.add(cbePrice);
						}
					}
					BeanUtil.setPropertySilent(reEntity, arr[1], getPriceByType(toPrice, "lower"));
					BeanUtil.setPropertySilent(reEntity, arr[2], getPriceByType(toPrice, "hight"));

				}
				if (!fromPrice.isEmpty() && !toPrice.isEmpty()) {
					BeanUtil.setProperty(entity, arr[1], getPriceByType(fromPrice, "lower") + getPriceByType(toPrice, "lower"));
					BeanUtil.setProperty(entity, arr[2], getPriceByType(fromPrice, "hight") + getPriceByType(toPrice, "hight"));
				}

			}

		} finally {
			fromPrice.clear();
			fromPrice = null;
			toPrice.clear();
			toPrice = null;
			fromToPrice.clear();
			fromToPrice = null;
			singleEntity = null;
			doubleEntity = null;
		}
	}
	
	/**
	 * 根据type获得最低价或者最高价
	 * 
	 * @param prices
	 * @param type
	 * @return
	 */
	public Double getPriceByType(List<Double> prices, String type) {
		if (type == null) {
			return null;
		}
		if (prices == null || prices.isEmpty()) {
			return null;
		}
		if (prices.size() == 1) {
			return prices.get(0);
		}
		Collections.sort(prices);
		if ("hight".equals(type)) {
			return prices.get(prices.size() - 1);
		} else if ("lower".equals(type)) {
			return prices.get(0);
		} else {
			return null;
		}
	}
	
	public static void main(String[] args) throws Exception {
		TaskModel taskQueue = new TaskModel();
		taskQueue.setIsInternational(0);
		taskQueue.setIsReturn(0);
		taskQueue.setFlightDate("2014-10-19");
		taskQueue.setReturnGrabDate("2014-10-22");
		taskQueue.setFromCity("TAO");
		taskQueue.setFromCityName("青岛");
		taskQueue.setToCity("PEK");
		taskQueue.setToCityName("北京");
		ShandongAirAdapter apdater = new ShandongAirAdapter(taskQueue);
//		apdater.fetch(null);
		List<Object> list = apdater.paraseToVo(apdater.fetch(""));
		apdater.printJson(list, "f:/shandong.txt");
	}
	
	@Override
	public String getUrl() throws Exception {
		// TODO Auto-generated method stub
		return null;
	}

	

}
